<?php
namespace base;

use ReflectionClass;
use ReflectionMethod;

class BaseLogic
{
	//时间分隔标识
	protected $btflag=' - ';

	/**
	 * 根据查询数组，构建查询条件
	 * @param  [type] $param [description]
	 * @return [type]        [description]
	 */
	protected function buildwhere($obj,$param,$config=[],$alias=''){

		if(empty($param)||empty($config)){
			return $obj;
		}

		foreach($config as $k=>$v){
			if(!isset($param[$k])||(empty($param[$k])&&$param[$k]!==0&&$param[$k]!=='0'))  continue;
			
			switch ($v[1]) {
				case 'like':
					$obj=$obj->whereLike($v[0],'%'.$param[$k].'%');
					break;

				case 'time':
				
					list($start,$end)=explode($this->btflag,$param[$k]);
					

					$obj=$obj->whereBetweenTime($v[0],$start,$end);

					break;
				
				default:

					$obj=$obj->where($v[0],$v[1],$param[$k]);
					break;
			}

			if(!empty($v[2])&&$v[2]==1){
				return $obj;
			}
		}
		if(!empty($param['test'])){
			$obj=$obj->fetchSql();
		}
		return $obj;
	}

	/**
	 * 前置逻辑处理
	 *
	 * @param mixed ...$param 可变参数列表
	 * @return void
	 */
	protected function beforeAction(&...$param)
	{
		$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,3);
		$method = new ReflectionMethod($trace[1]['class'],$trace[1]['function']);
		$namespace = (new ReflectionClass($trace[1]['class']))->getNamespaceName();
		$actionList = $this->parseConfig($method,'before',$namespace);
		if(empty($actionList))return true;
		
        $call_method = $trace[2]['class'].'.'.$trace[2]['function'];

		foreach ($actionList as $name=>$action) {
			if(is_array($action)){
				if(!empty($action['only'])&&!in_array($call_method,$action['only']))continue;
				if(!empty($action['except'])&&in_array($call_method,$action['except']))continue;
				$action = $name;
			}

			$actionArr = explode('.',$action);
			if(count($actionArr)==1){
				$res = $this->$action(...$param);
			}else{
				$method = $actionArr[1];
				$class = strpos($actionArr[0],'\\')?$actionArr[0]:$namespace.'\\lib\\'.$actionArr[0];
				$res = (new $class())->$method(...$param);
			}
			
			if(!$res){
				return false;
			}
		}

	}

	/**
	 * 后置逻辑处理
	 *
	 * @param mixed ...$param 可变参数列表
	 * @return void
	 */
	protected function afterAction(&...$param)
	{
		$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,3);
        $method = new ReflectionMethod($trace[1]['class'],$trace[1]['function']);
		$namespace = (new ReflectionClass($trace[1]['class']))->getNamespaceName();
		$actionList = $this->parseConfig($method,'after',$namespace);
		if(empty($actionList))return true;
		
        $call_method = $trace[2]['class'].'.'.$trace[2]['function'];

		foreach ($actionList as $name=>$action) {
			if(is_array($action)){
				if(!empty($action['only'])&&!in_array($call_method,$action['only']))continue;
				if(!empty($action['except'])&&in_array($call_method,$action['except']))continue;
				$action = $name;
			}
			
			$actionArr = explode('.',$action);
			if(count($actionArr)==1){
				$res = $this->$action(...$param);
			}else{
				$method = $actionArr[1];
				$class = strpos($actionArr[0],'\\')?$actionArr[0]:$namespace.'\\lib\\'.$actionArr[0];
				$res = (new $class())->$method(...$param);
			}
			
			if(!$res){
				return false;
			}
		}
	}

	/**
	 * 根据注释构建前置后置配置
	 *
	 * @param ReflectionMethod $method
	 * @param string $type
	 * @return array
	 */
	protected function parseConfig(ReflectionMethod $method,$type,$namespace)
	{
		/**
		 * 前置后置注释示例
		 * 
		 * @before(test,test|only|app\controller\test.action1&app\controller\test.action2)
		 * @after(app\lib\test.test|except|app\controller\test.actoion1)
		 */
		$docString = $method->getDocComment();

		$docString = str_replace(["/**","*/"," *"],'',$docString);//过滤 注释标识符

        $list  = explode("@",$docString);//拆分注释内容

		$newConfig = [];

        foreach ($list as $key => $value) {
            if($key==0){//拆分后第一个值为注释描述
                $this->comment = trim($value);
                continue;
            }
            $arr = explode('(',$value);//根据商定格式解析每个值
            if($arr[0]==$type){//配置类型相匹配处理配置
				$str = str_replace(')','',trim($arr[1]??''));
                $configs = explode(',',$str);

				foreach ($configs as $key=>$config) {
					$carr = explode('|',trim($config));
					if(count($carr)==1){
						$newConfig[$key]=$config;
					}else{
						if(empty($carr[1])||empty($carr[2])){
							$newConfig[$key]=$carr[0];
							continue;
						}
						$functions = [];
						foreach (explode('&',$carr[2]) as $key => $value) {
							$functions[$key] = strpos($value,'\\')?$value:str_replace('logic','controller',$namespace.'\\'.$value);
						}

						$newConfig[$carr[0]][$carr[1]]=$functions;
					}
				}
            }
        }

		return $newConfig;
	}

}